#include "console.h"
#include "ports.h"
/**
 * vga 打印字符的其实位置
 *
 */
static uint16_t *video_memory = (uint16_t *)0xb8000;
/**
 * 光标的横竖位置
 * 横：80个长度
 * 树：20个长度
 */
static uint8_t cursor_x = 0;
static uint8_t cursor_y = 0;

/**
 * 移动光标到x.y
 *
 */
static void move_cursor()
{
    uint16_t cursor_loc = cursor_y * 80 + cursor_x;
    // 告诉VGA 我们要设置的光标 高字节
    outb(0x3d4, 14);
    // 发送高位8位字节
    outb(0x3d5, cursor_loc >> 8);
    // 告诉VGA，我们要设置的光标 低字节
    outb(0x3d4, 15);
    // 发送低8位字节
    outb(0x3d5, cursor_loc);
}
/**
 * 清理屏幕
 *
 */
void console_clear()
{
    // 被构造出一个黑底白字的描述格式
    uint8_t attr_byte = (0 << 4) | (15 & 0x0f);
    uint16_t blank = 0x20 | (attr_byte << 8);
    int i;
    for (i = 0; i < CURSOR_X_MAX * CURSOR_Y_MAX; i++)
    {
        video_memory[i] = blank;
    }
    cursor_x = cursor_y = 0;
    move_cursor();
}
/**
 * @屏幕滚动
 *
 */

static void scroll()
{
    // 被构造出一个黑底白字的描述格式
    uint8_t attr_byte = (0 << 4) | (15 & 0x0f);
    uint16_t blank = 0x20 | (attr_byte << 8);
    if (cursor_y >= CURSOR_Y_MAX)
    {
        int i;
        for (i = 0; i < (CURSOR_Y_MAX - 1) * CURSOR_X_MAX; i++)
        {
            video_memory[i] = video_memory[i + CURSOR_X_MAX];
        }
        for (i = (CURSOR_Y_MAX - 1) * CURSOR_X_MAX; i < CURSOR_X_MAX * CURSOR_Y_MAX; i++)
        {
            video_memory[i] = blank;
        }
        cursor_y = CURSOR_Y_MAX - 1;
    }
}
/**
 * 显示字符串
 *
 */
void console_putc_color(char c, real_color_t back, real_color_t fore)
{
    uint8_t back_color = (uint8_t)back;
    uint8_t fore_color = (uint8_t)fore;

    uint8_t attribute_byte = (back_color << 4) | (fore_color & 0x0F);
    uint16_t attribute = attribute_byte << 8;

    // 0x08 是退格键的 ASCII 码
    // 0x09 是tab 键的 ASCII 码
    if (c == 0x08 && cursor_x)
    {
        cursor_x--;
    }
    else if (c == 0x09)
    {
        cursor_x = (cursor_x + 8) & ~(8 - 1);
    }
    else if (c == '\r')
    {
        cursor_x = 0;
    }
    else if (c == '\n')
    {
        cursor_x = 0;
        cursor_y++;
    }
    else if (c >= ' ')
    {
        video_memory[cursor_y * 80 + cursor_x] = c | attribute;
        cursor_x++;
    }

    // 每 80 个字符一行，满80就必须换行了
    if (cursor_x >= 80)
    {
        cursor_x = 0;
        cursor_y++;
    }

    // 如果需要的话滚动屏幕显示
    scroll();

    // 移动硬件的输入光标
    move_cursor();
}

void console_write(char *cstr)
{
    while (*cstr)
    {
        console_putc_color(*cstr++, rc_black, rc_white);
    }
}

void console_write_color(char *cstr, real_color_t back, real_color_t fore)
{
    while (*cstr)
    {
        console_putc_color(*cstr++, back, fore);
    }
}